/****************************************************************************
**
** Copyright (C) 2009-2010 Mist Poryvaev.
** All rights reserved.
** Contact: Mist Poryvaev (mist.poryvaev@gmail.com)
**
** This file is part of the RailWorm project.
**
****************************************************************************/

#include "parsetraindata.h"
#include "connectrzd.h"

// -------------------------------------------------------

TableEventHandler::TableEventHandler(ParseTrainData *PTD)
	: QObject(), m_PTD(PTD), m_PrevItem(0) {
	m_PTD->m_TableEventHandler = this;
	m_PTD->m_Table->startTimer(100);
	QIcon IconLogo(":/railworm/logo_rzd.png");
	m_NameButton = new QPushButton(m_PTD->m_Table);
	m_NameButton->setIcon(IconLogo);
	m_NameButton->setMaximumSize(QSize(48, 24));
	m_NameButton->setFlat(true);
	m_NameButton->setToolTip(tr("Переход на страницу поезда"));
	m_NameButton->hide();
	connect(m_NameButton, SIGNAL(clicked()), this, SLOT(NameButtonClicked()));
	m_PathButton = new QPushButton(m_PTD->m_Table);
	m_PathButton->setIcon(IconLogo);
	m_PathButton->setMaximumSize(QSize(48, 24));
	m_PathButton->setFlat(true);
	m_PathButton->setToolTip(tr("Переход на страницу расписания"));
	m_PathButton->hide();
	connect(m_PathButton, SIGNAL(clicked()), this, SLOT(PathButtonClicked()));

	QIcon IconOrder(":/railworm/order.png");
	m_OrderButton = new QPushButton(m_PTD->m_Table);
	m_OrderButton->setIcon(IconOrder);
	m_OrderButton->setMaximumSize(QSize(48, 24));
	m_OrderButton->setFlat(true);
	m_OrderButton->setToolTip(tr("Заказ билетов"));
	m_OrderButton->hide();

// временно закрываем
	connect(m_OrderButton, SIGNAL(clicked()), this, SLOT(OrderButtonClicked()));
}

void TableEventHandler::Reset() {
	m_PrevItem = 0;
}

bool TableEventHandler::eventFilter(QObject * obj, QEvent * ev) {
	if (ev->type() == QEvent::Timer) {
		QPoint pos = QCursor::pos();
		pos.setY(pos.y() - m_PTD->m_Table->horizontalHeader()->height());
		QTableWidgetItem * Item = m_PTD->m_Table->itemAt(m_PTD->m_Table->mapFromGlobal(pos));
		if (m_PrevItem != Item) {
			m_NameButton->hide();
			m_PathButton->hide();
			m_OrderButton->hide();
			if (m_PrevItem) {
				QFont fnt(m_PrevItem->font());
				fnt.setBold(false);
				m_PrevItem->setFont(fnt);
			}
			m_PrevItem = Item;
			if (m_PrevItem) {
				QFont fnt(m_PrevItem->font());
				fnt.setBold(true);
				m_PrevItem->setFont(fnt);

				QPoint TopRight = m_PTD->m_Table->visualItemRect(m_PrevItem).topRight();
				TopRight.setY(TopRight.y() + m_PTD->m_Table->horizontalHeader()->height());
				TopRight.setX(TopRight.x() - 32);

				if (m_PrevItem->column() == ParseTrainData::COL_NAME) {
					m_NameButton->move(TopRight);
					m_NameButton->show();
				}

				if (m_PrevItem->column() == ParseTrainData::COL_PATH) {
					m_PathButton->move(TopRight);
					m_PathButton->show();
				}

				if ((m_PrevItem->column() == ParseTrainData::COL_PRICE) || (m_PrevItem->column() == ParseTrainData::COL_NUMBER)) {
					m_OrderButton->move(TopRight);
					m_OrderButton->show();
				}
			}
		}
	}
	return QObject::eventFilter(obj, ev);
}

void TableEventHandler::NameButtonClicked() {
	if (m_PrevItem) {
		m_PTD->OpenUrl(m_PrevItem->row(), m_PrevItem->column());
	}
}

void TableEventHandler::PathButtonClicked() {
	if (m_PrevItem) {
		m_PTD->OpenUrl(m_PrevItem->row(), m_PrevItem->column());
	}
}

void TableEventHandler::OrderButtonClicked() {
	if (m_PrevItem) {
		m_PTD->Order(m_PrevItem->row(), m_PrevItem->column());
	}
}

// -------------------------------------------------------

ParseTrainData::ParseTrainData(QObject * Parent): QObject(Parent) {
	m_SubPagesCount = 0;
	m_FirmTrains = 0;
	m_Collapsable = true;
	m_SeatsDetailsVisible = false;
	m_CurrentData = & m_SessionData;
	m_Class_Id = 0;

	m_Filter = new QLineEdit();
	connect(m_Filter, SIGNAL(returnPressed()), this, SLOT(OnFilterChanged()));
	m_TableType = new QComboBox();
	m_TableType->setEditable(false);
	m_TableType->addItem(QIcon(":/railworm/empty_star.png"), tr("Все"), TABLE_ALL);
	m_TableType->addItem(QIcon(":/railworm/star.png"), tr("Избранные"), TABLE_FAV);
	connect(m_TableType, SIGNAL(currentIndexChanged(int)), this, SLOT(TableTypeChanged(int)));
	QHBoxLayout * FilterLayout = new QHBoxLayout();
	FilterLayout->setMargin(0);
	FilterLayout->addWidget(new QLabel(tr("Фильтр ")));
	FilterLayout->addWidget(m_Filter);
	FilterLayout->addWidget(m_TableType);

	m_Table = new QTableWidget();
	m_Table->setColumnCount(COLS_COUNT);
	m_Table->verticalHeader()->hide();
	m_Table->horizontalHeader()->setClickable(true);
	m_Table->setSelectionMode(QTableWidget::NoSelection);
	m_Table->installEventFilter(new TableEventHandler(this));
	connect(m_Table->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(OnSort(int)));
	connect(m_Table, SIGNAL(cellDoubleClicked(int,int)), this, SLOT(OpenUrl(int,int)));
	connect(m_Table, SIGNAL(cellClicked(int,int)), this, SLOT(MarkFavorite(int,int)));
	connect(m_Table, SIGNAL(cellDoubleClicked(int,int)), this, SLOT(Order(int,int)));
	CreateTableHeaders();

	Print(); // печатаем пустой список

	QVBoxLayout * WidgetLayout = new QVBoxLayout();
	WidgetLayout->setMargin(0);
	WidgetLayout->addLayout(FilterLayout);
	WidgetLayout->addWidget(m_Table);

	m_Widget = new QWidget();
	m_Widget->setLayout(WidgetLayout);
}

ParseTrainData::~ParseTrainData() {

}

void ParseTrainData::SetFirmTrainsList(FirmTrainsList * FirmTrains) {
	m_FirmTrains = FirmTrains;
}

void ParseTrainData::CreateTableHeaders() {
	QTableWidgetItem * It;

	m_Table->setColumnWidth(COL_NAME, 100);
	m_Table->setHorizontalHeaderItem(COL_NAME, It = new QTableWidgetItem(tr("Поезд")));
	It->setToolTip(tr("Номер и название поезда"));

	m_Table->setColumnWidth(COL_PATH, 110);
	m_Table->setHorizontalHeaderItem(COL_PATH, It = new QTableWidgetItem(tr("Маршрут")));
	It->setToolTip(tr("Начальная и конечная станции следования поезда (полный маршрут)"));

	m_Table->setColumnWidth(COL_START, 50);
	m_Table->setHorizontalHeaderItem(COL_START, It = new QTableWidgetItem(tr("Отпр.")));
	It->setToolTip(tr("Время отправления"));

	m_Table->setColumnWidth(COL_END, 50);
	m_Table->setHorizontalHeaderItem(COL_END, It = new QTableWidgetItem(tr("Приб.")));
	It->setToolTip(tr("Время прибытия"));

	m_Table->setColumnWidth(COL_DELTA, 50);
	m_Table->setHorizontalHeaderItem(COL_DELTA, It = new QTableWidgetItem(tr("В пути")));
	It->setToolTip(tr("Время следования между запрошенными станциями"));

	m_Table->setColumnWidth(COL_CLASS, 100);
	m_Table->setHorizontalHeaderItem(COL_CLASS, It = new QTableWidgetItem(tr("Класс")));
	It->setToolTip(tr("Класс"));

	m_Table->setColumnWidth(COL_CATEGORY, 45);
	m_Table->setHorizontalHeaderItem(COL_CATEGORY, It = new QTableWidgetItem(tr("Кат.")));
	It->setToolTip(tr("Категория"));

	m_Table->setColumnWidth(COL_PRICE, 100);
	m_Table->setHorizontalHeaderItem(COL_PRICE, It = new QTableWidgetItem(tr("Цена")));
	It->setToolTip(tr("Цена"));

	m_Table->setColumnWidth(COL_NUMBER, 30);
	m_Table->setHorizontalHeaderItem(COL_NUMBER, It = new QTableWidgetItem(tr("№")));
	It->setToolTip(tr("Номер вагона"));

	m_Table->setColumnWidth(COL_TOTALPLACES, 80);
	m_Table->setHorizontalHeaderItem(COL_TOTALPLACES, It = new QTableWidgetItem(tr("Кол-во мест")));
	It->setToolTip(tr("Обшее количество доступных мест"));

	m_Table->setColumnWidth(COL_UPPERPLACES, 65);
	m_Table->setHorizontalHeaderItem(COL_UPPERPLACES, It = new QTableWidgetItem(tr("Верх. куп.")));
	It->setToolTip(tr("Количество верхних купейных мест"));

	m_Table->setColumnWidth(COL_LOWERPLACES, 65);
	m_Table->setHorizontalHeaderItem(COL_LOWERPLACES, It = new QTableWidgetItem(tr("Ниж. куп.")));
	It->setToolTip(tr("Количество нижних купейных мест"));

	m_Table->setColumnWidth(COL_UPPERSIDEPLACES, 65);
	m_Table->setHorizontalHeaderItem(COL_UPPERSIDEPLACES, It = new QTableWidgetItem(tr("Верх. бок.")));
	It->setToolTip(tr("Количество верхних боковых мест"));

	m_Table->setColumnWidth(COL_LOWERSIDEPLACES, 65);
	m_Table->setHorizontalHeaderItem(COL_LOWERSIDEPLACES, It = new QTableWidgetItem(tr("Ниж. бок.")));
	It->setToolTip(tr("Количество нижних боковых мест"));

	m_Table->setColumnWidth(COL_OTHERPLACES, 65);
	m_Table->setHorizontalHeaderItem(COL_OTHERPLACES, It = new QTableWidgetItem(tr("Другие")));
	It->setToolTip(tr("Количество сидячих и прочих мест"));
}

void ParseTrainData::Exec(const QString & From, const QString & To, const QString & DateStart, const QString & DateEnd) {
	m_TableEventHandler->Reset();
	m_Table->clearContents();
	m_Table->setRowCount(0);
	m_Table->clearSpans();

	QDate _DateStart = QDate::fromString(DateStart, "dd.MM");
	QDate _DateEnd = QDate::fromString(DateEnd, "dd.MM");

	if (_DateStart < QDate::currentDate()) {
		_DateStart.addYears(1);
	}
	if (_DateEnd < QDate::currentDate()) {
		_DateEnd.addYears(1);
	}

	m_MainPagesCount = 0;
	m_MainPagesFinished = 0;
//	m_MainPagesId.clear();
	m_TempSessionData.clear();
	m_From = From;
	m_To = To;
	QDate _It = _DateStart;
	while (_It <= _DateEnd) {
/*
		QByteArray postData =
				QByteArray("&src=") +
				From.toLocal8Bit().toPercentEncoding() +
				QByteArray("&dst=") +
				To.toLocal8Bit().toPercentEncoding() +
				QByteArray("&date=") +
				_It.toString("dd.MM").toLocal8Bit();

		int _Id = rzd::Request(
				rzd::PassHost(),
				rzd::Query("MainPage") + postData,
				rzd::Form,
				rzd::Local8Bit,
				this,
				SLOT(OnMainPageRequestFinished(QString,int,bool)));
		m_MainPagesId << _Id;
*/
		QString _post_data = "&src=" +
							 From.toLocal8Bit().toPercentEncoding() +
							 "&dst=" +
							 To.toLocal8Bit().toPercentEncoding() +
							 "&date=" +
							 _It.toString("dd.MM");
		jinn.Request(
				"http://" + rzd::PassHost() + rzd::Query("MainPage") + _post_data,
				HtmlGenie::ContentTypeForm(),
				this,
				SLOT(OnMainPageRequestFinished(HtmlResponse *,int,bool))
				);

		m_MainPagesCount++;
		_It = _It.addDays(1);

		qApp->processEvents();
	}


}

void ParseTrainData::OnMainPageRequestFinished(HtmlResponse * Response, int Id, bool _Error) {
	m_MainPagesFinished++;
	m_SessionData.clear();
	if (_Error == false) {
		ParseMainPage(Response);
		m_TempSessionData << m_SessionData;
	}

	delete Response;

	emit ProgressUpdate(m_MainPagesFinished, m_MainPagesCount);
	qDebug() << "OnMainPageRequestFinished" << QString::number(m_MainPagesFinished) << "/" << QString::number(m_MainPagesCount);
	if (m_MainPagesFinished != m_MainPagesCount) {
		if (_Error) {
			emit Error("OnMainPageRequestFinished error");
		}
		return;
	}

	m_SessionData = m_TempSessionData;
	m_TempSessionData.clear();

	m_SubPagesCount = 0;
	m_SubPagesFinished = 0;
//	m_SubPagesId.clear();
	for (TrainDataList::iterator It = m_SessionData.begin(); It != m_SessionData.end(); It++) {
		TrainDataStruct & TrainData = * It;
/*
		TrainData.Id = rzd::Request(
				rzd::PassHost(),
				TrainData.NameUrl.toLocal8Bit(),
				rzd::Text,
				rzd::Local8Bit,
				this,
				SLOT(OnSubPageRequestFinished(QString, int,bool)));
*/
		TrainData.Id = jinn.Request(
				"http://" + rzd::PassHost() + TrainData.NameUrl,
				HtmlGenie::ContentTypeText(),
				this,
				SLOT(OnSubPageRequestFinished(HtmlResponse*,int,bool))
				);
		//		connect(SubHttp, SIGNAL(dataReadProgress(int,int)), this, SIGNAL(ProgressUpdate(int,int)));
		// progress
//		connect(ResponseHandler::Reply(TrainData.Id), SIGNAL(downloadProgress(qint64,qint64)), this, SIGNAL(ProgressUpdate(qint64,qint64)));
		m_SubPagesCount++;
		qDebug() << "Requested, id =" << QString::number(TrainData.Id);

		qApp->processEvents();
	}

	emit MainPageFinished();
	if (m_SessionData.size() == 0) {
		emit SubPagesFinished();
	}

	if (_Error) {
		emit Error("OnMainPageRequestFinished error");
	}
}

void ParseTrainData::ParseMainPage(HtmlResponse * Response) {

	HtmlElementPars _pars;
	_pars.Class = "Striped";
	HtmlTableDataList _table_list = Response->Tables(_pars);
	qDebug() << "ParseMainPage _table_list.size() = " << _table_list.size();
	if (_table_list.size() == 0) {
		qDebug() << "bad mainpage";
		return;
	}

	TrainDataStruct TrainData;
	TrainDataList & TrainsData = m_SessionData;
	HtmlLinkDataList _links_list;
	QString _text;

	HtmlTableData _table = _table_list.at(0);
	foreach (const HtmlTableCellData & _cell, _table.Cells) {
		_text = _cell.Text.simplified().replace("&nbsp;", " ");
		switch (_cell.Column) {
			case 1:
				TrainData.OriginalName = _text;
				TrainData.Name = TrainData.OriginalName;
				if (m_FirmTrains) {
					foreach (FirmTrainStruct FirmTrain, * m_FirmTrains) {
						if ((FirmTrain.Number1 + "/" + FirmTrain.Number2).contains(TrainData.Name)) {
							TrainData.Name += "\n\"" + FirmTrain.Name + "\"";
							break;
						}
					}
				}
				break;
			case 2:
				_links_list = HtmlResponse::Links(_text);
				if (_links_list.size() > 0) {
					TrainData.PathUrl = _links_list.at(0).Url.toString();
					TrainData.Path = _links_list.at(0).Content;
				}
				break;
			case 3:
				TrainData.Start = _text;
			break;
			case 4:
				TrainData.End = _text;
			break;
			case 5:
				TrainData.Delta = _text;
				TrainData.Visible = true;
				TrainData.Favorite = false;
				TrainData.From = m_From;
				TrainData.To = m_To;

				TrainData.NameUrl = TrainData.PathUrl;
				TrainData.NameUrl.replace("&refererLayerId=", "").replace("&schd_ref_id=1", "").replace("&layer_id=", "").replace("schd_id=3&", "");
				TrainData.NameUrl += "&schd_id=6";
				TrainData.NameUrl += "&sheet=p62g60";
				TrainData.NameUrl = TrainData.NameUrl.toUtf8().toPercentEncoding(QByteArray(":/=_&?"));

				TrainsData << TrainData;
			break;
		}
	}

/*
	bool TR_Found = false, TD_Found = false, TD_MultiLine = false;
	int Count = 0;

	TrainDataStruct TrainData;
	TrainDataList & TrainsData = m_SessionData;

	bool TableFound = false;
	QStringList Table;
	foreach(QString Line, Response.split("\n", QString::SkipEmptyParts)) {
		if (Line.contains("Striped")) {
			TableFound = true;
		}
		if (TableFound) {
			Table << Line;
		}
		if (TableFound && Line.contains("</table>")) {
			break;
		}
	}

//	qDebug() << "---------------------------";
//	qDebug() << Table.size();
	QString Data, DataHref, Data2;
	QString FullLine;
	foreach(QString Line, Table) {
		if (TD_Found) {
			if (TD_MultiLine) {
				FullLine += Line;
			}
			if (FullLine.contains("</td>")) {
				TD_Found = false;
				if (FullLine.contains("href=\"")) {
					DataHref = FullLine.split("href=\"").at(1).split("\"").at(0);
					if (DataHref.at(0) != '/') {
						DataHref = "/" + DataHref;
					}
					Data2 = FullLine.split('>').at(2).split('<').at(0);
					Data2.replace("&nbsp;", " ");
				}
				else {
					Data = FullLine.split('>').at(1).split('<').at(0);
					Data.replace("&nbsp;", " ");
				}
//				qDebug() << Count << "FullLine = " << FullLine;
				switch (Count) {
					case 0: {
							break;
						}
					case 1:
						Data.replace(' ', "");
						TrainData.OriginalName = Data;
						TrainData.Name = Data;
						if (m_FirmTrains) {
							foreach (FirmTrainStruct FirmTrain, * m_FirmTrains) {
								if ((FirmTrain.Number1 + "/" + FirmTrain.Number2).contains(TrainData.Name)) {
									TrainData.Name += "\n\"" + FirmTrain.Name + "\"";
									break;
								}
							}
						}
//						TrainData.NameUrl = DataHref; // теперь не работает
//						qDebug() << TrainData.Name;
						break;
					case 2:
						TrainData.Path = Data2;
						TrainData.PathUrl = DataHref;
						break;
					case 3:
						TrainData.Start = Data;
						break;
					case 4:
						TrainData.End = Data;
						break;
					case 5:
						TrainData.Delta = Data;
						TrainData.Visible = true;
						TrainData.Favorite = false;
						TrainData.From = m_From;
						TrainData.To = m_To;

						TrainData.NameUrl = TrainData.PathUrl;
						TrainData.NameUrl.replace("&refererLayerId=", "").replace("&schd_ref_id=1", "").replace("&layer_id=", "").replace("schd_id=3&", "");
						TrainData.NameUrl += "&schd_id=6";
						TrainData.NameUrl += "&sheet=p62g60";
						TrainData.NameUrl = TrainData.NameUrl.toUtf8().toPercentEncoding(QByteArray(":/=_&?"));

						TrainsData << TrainData;
						break;
				}

				Count++;
				Data = "";
				Data2 = "";
			}
		}
		if (TR_Found) {
			if (Line.contains("<td")) {
				TD_Found = true;
				FullLine = Line;
				TD_MultiLine = !Line.contains("</td>");
			}
		}
		if (Line.contains("<tr>")) {
			TR_Found = true;
//			qDebug() << "<tr>";
		}
		if (Line.contains("</tr>")) {
			TR_Found = false;
			TD_Found = false;
			Count = 0;
//			qDebug() << "</tr>";
		}
	}
*/
/*
  // нет поездов в этот день
	if (m_SessionData.size() == 0) {
		emit Error(tr("Неправильный запрос"));
	}
*/
}

void ParseTrainData::OnSubPageRequestFinished(HtmlResponse * Response, int Id, bool _Error) {
	m_SubPagesFinished++;
	if (_Error == false) {
		ParseSubPage(Response, Id);
	}

	delete Response;

	emit ProgressUpdate(m_SubPagesFinished, m_SubPagesCount);

	qDebug() << "OnSubPageRequestFinished"
			<< QString::number(m_SubPagesFinished) + "/" + QString::number(m_SubPagesCount);
	if (m_SubPagesCount == m_SubPagesFinished) {
		SortBy(COL_START);
		emit SubPagesFinished();
	}
	emit SubPagesProcessing();

	if (_Error) {
		emit Error("OnSubPageRequestFinished error");
	}

}

void ParseTrainData::ParseSubPage(HtmlResponse * Response, int Id) {

	HtmlElementPars _pars;
	_pars.Class = "result pStripedBlue";
	HtmlTableDataList _table_list = Response->Tables(_pars);
	if (_table_list.size() == 0) {
		qDebug() << "bad subpage";

		QPlainTextEdit * te = new QPlainTextEdit();
		te->setPlainText(Response->Data());
		te->show();

		return;
	}

	ClassesStruct Class, * Prev_Class = 0;
	CarDataStruct Car;
	TrainDataList & TrainsData = m_SessionData;
	TrainDataList::iterator It;
	QString _text;

	HtmlTableData _table = _table_list.at(0);
	HtmlInputDataList _inputs_list;
	foreach (const HtmlTableCellData & _cell, _table.Cells) {
		_text = _cell.Text.simplified().replace("&nbsp;", "");
		switch (_cell.Column) {
			case 0:
				_inputs_list = HtmlResponse::Inputs(_text);
				if (_inputs_list.size() > 0) {
					if (Class.Class.isEmpty() == false) {
						It = TrainsData.begin();
						for (; It != TrainsData.end(); It++) {
							if (It->Id == Id) {
								CreateAdvClassDesc(Class);
								Class.Visible = true;
								// проверяем, не является ли класс таким же, как предыдущий
								if (Prev_Class != 0) {
									if ((Prev_Class->Class == Class.Class) && (Prev_Class->Category == Class.Category) && (Prev_Class->Price == Class.Price)) {
										Prev_Class->Car << Class.Car;
										Class = ClassesStruct();
										break;
									}
								}
								// -----------
								Class.Id = m_Class_Id++;
								It->Class << Class;
								Prev_Class = & It->Class.back();
								Class = ClassesStruct();
								break;
							}
						}
					}
					Car.VehicleCode = tr(_inputs_list.at(0).Value.toLocal8Bit());
//					qDebug() << "VehicleCode = " << Car.VehicleCode;
				}
			break;
			case 1:
				Class.Class = _text;
			break;
			case 2:
				Class.Category = _text;
			break;
			case 3:
			break;
			case 4:
			break;
			case 5:
				Car.Number = _text.replace(" ", "");
			break;
			case 6:
				Class.Price = _text.replace(" ", "");;
			break;
			case 7:
				Car.UpperPlaces = _text.replace(" ", "");;
			break;
			case 8:
				Car.LowerPlaces = _text.replace(" ", "");;
			break;
			case 9:
				Car.UpperSidePlaces = _text.replace(" ", "");;
			break;
			case 10:
				Car.LowerSidePlaces = _text.replace(" ", "");;
			break;
			case 11:
				Car.OtherPlaces = _text.replace(" ", "");
				Class.Car << Car;
				Car = CarDataStruct();
			break;

		}
	}

	if (Class.Class.isEmpty() == false) {
		It = TrainsData.begin();
		for (; It != TrainsData.end(); It++) {
			if (It->Id == Id) {
				qDebug() << "SubPage found, id =" << QString::number(Id);
				CreateAdvClassDesc(Class);

				Class.Visible = true;
				// проверяем, не является ли класс таким же, как предыдущий
				if (Prev_Class != 0) {
					if ((Prev_Class->Class == Class.Class) && (Prev_Class->Category == Class.Category) && (Prev_Class->Price == Class.Price)) {
						Prev_Class->Car << Class.Car;
						break;
					}
				}
				// -----------
				Class.Id = m_Class_Id++;
				It->Class << Class;

				break;
			}
		}
	}


/*
	bool TR_Found = false, TD_Found = false, TD_MultiLine = false;
	int Count = 0;
	ClassesStruct Class, * Prev_Class = 0;
	CarDataStruct Car;
	TrainDataList & TrainsData = m_SessionData;
	TrainDataList::iterator It;
	QString FullLine;
	bool TableFound = false;
	QVector<QStringList> Table;
	foreach(QString Line, Response.split("\n", QString::SkipEmptyParts)) {
		if (Line.contains("Striped")) {
			TableFound = true;
			Table.push_back(QStringList());
		}
		if (TableFound) {
			Table.back() << Line;
		}
		if (TableFound && Line.contains("</table>")) {
			TableFound = false;
			if (Table.size() == 2) {
				break;
			}
		}
	}
*/
//	QMessageBox::information(0, "", QString::number(Table.back().size()));
/*
	QString Data;
	foreach (QString Line, Table.back()) {
		if (TD_Found) {
			if (TD_MultiLine) {
				FullLine += Line;
			}
			if (FullLine.contains("</td>")) {
				TD_Found = false;

//				qDebug() << Count << FullLine;

				Data = FullLine.split('>').at(1).split('<').at(0);
				Data.replace('\n', "").replace('\r', "").replace(' ', "").replace("&nbsp;", " ");

				switch (Count) {
					case 0:
						if (Class.Class.isEmpty() == false) {
							It = TrainsData.begin();
							for (; It != TrainsData.end(); It++) {
								if (It->Id == Id) {
									CreateAdvClassDesc(Class);
									Class.Visible = true;
									// проверяем, не является ли класс таким же, как предыдущий
									if (Prev_Class != 0) {
										if ((Prev_Class->Class == Class.Class) && (Prev_Class->Category == Class.Category) && (Prev_Class->Price == Class.Price)) {
											Prev_Class->Car << Class.Car;
											Class = ClassesStruct();
											break;
										}
									}
									// -----------
									Class.Id = m_Class_Id++;
									It->Class << Class;
									Prev_Class = & It->Class.back();
									Class = ClassesStruct();
									break;
								}
							}
						}
						Car.VehicleCode = FullLine.split("value=\"").at(1).split("\">").at(0);
						Car.VehicleCode = Car.VehicleCode.left(Car.VehicleCode.length() - 3) + FullLine.split("'serviceClass', '").at(1).split("');").at(0);
						break;
					case 1:
						Class.Class = Data;
						break;
					case 2:
						Class.Category = Data;
						break;
					case 3:
						break;
					case 4:
						break;
					case 5:
						Car.Number = Data.replace(" ", "");
						break;
					case 6:
						Class.Price = Data.replace(" ", "");;
						break;
					case 7:
						Car.UpperPlaces = Data.replace(" ", "");;
						break;
					case 8:
						Car.LowerPlaces = Data.replace(" ", "");;
						break;
					case 9:
						Car.UpperSidePlaces = Data.replace(" ", "");;
						break;
					case 10:
						Car.LowerSidePlaces = Data.replace(" ", "");;
						break;
					case 11:
						Car.OtherPlaces = Data.replace(" ", "");
						Class.Car << Car;
						Car = CarDataStruct();
						break;
				}

				Count++;
			}
		}

		if (TR_Found) {
			if (Line.contains("<td")) {
				TD_Found = true;
				FullLine = Line;
				TD_MultiLine = !Line.contains("</td>");
			}
		}
		if (Line.contains("<tr>")) {
			TR_Found = true;
			Count = 0;
		}
		if (Line.contains("</tr>")) {
			TR_Found = false;
			Count = 0;
		}
	}

	if (Class.Class.isEmpty() == false) {
		It = TrainsData.begin();
		for (; It != TrainsData.end(); It++) {
			if (It->Id == Id) {
				qDebug() << "SubPage found, id =" << QString::number(Id);
				CreateAdvClassDesc(Class);

				Class.Visible = true;
				// проверяем, не является ли класс таким же, как предыдущий
				if (Prev_Class != 0) {
					if ((Prev_Class->Class == Class.Class) && (Prev_Class->Category == Class.Category) && (Prev_Class->Price == Class.Price)) {
						Prev_Class->Car << Class.Car;
						break;
					}
				}
				// -----------
				Class.Id = m_Class_Id++;
				It->Class << Class;

				break;
			}
		}
	}
*/
}

bool PriceSort(ClassesStruct & c1, ClassesStruct & c2) {
	if (c1.Visible != c2.Visible) {
		if (c1.Visible) {
			return true;
		}
		if (c2.Visible) {
			return false;
		}
	}
	return c1.Price.replace("&nbsp;", "").split("-").at(0).toFloat() <= c2.Price.replace("&nbsp;", "").split("-").at(0).toFloat();
}

#define ADV_CLASS(t1, t2) if (Class.Class.contains(tr(t1), Qt::CaseInsensitive)) { Class.AdvDesc.Class = tr(t2); }
#define ADV_SERVICE(t1, t2) if (Class.Class.contains(tr(t1), Qt::CaseInsensitive)) { Class.AdvDesc.Service = tr(t2); Class.AdvDesc.Class += tr("\n(") + tr(t1) + ")"; }
#define ADV_CAT(t1, t2) if (Class.Category.contains(tr(t1), Qt::CaseInsensitive)) { if (Class.AdvDesc.Category.isEmpty() == false) { Class.AdvDesc.Category += "<br/><br/>"; }  Class.AdvDesc.Category += tr(t2); }
void ParseTrainData::CreateAdvClassDesc(ClassesStruct & Class) {
	ADV_CLASS("люкс", "Люкс");
	ADV_CLASS("мягк", "Мягкий");
	ADV_CLASS("купе", "Купейный");
	ADV_CLASS("плац", "Плацкартный");
	ADV_CLASS("сид",  "Сидячий");

	ADV_SERVICE("1А", "<b>VIP</b><br/>(наличие установки кондиционирования воздуха)");
	ADV_SERVICE("1Б", "<b>Бизнес-класс</b><br/>(вагон СВ с услугами,наличие установки кондиционирования воздуха)");
	ADV_SERVICE("1И", "<b>VIP</b>");
	ADV_SERVICE("1Л", "<b>Люкс</b><br/>(вагон СВ без услуг, наличие установки кондиционирования воздуха)");
	ADV_SERVICE("1М", "<b>Продается только целое купе</b><br/>(в купе возможно оформить проезд на одного или двух пассажиров)");
	ADV_SERVICE("1Н", "<b>Премиум</b><br/>(в стоимость входит горячий завтрак)");
	ADV_SERVICE("1С", "<b>Бизнес-класс</b><br/>(вагон с услугами, наличие установки кондиционирования воздуха)");
	ADV_SERVICE("1У", "<b>1 класс-стандарт</b><br/>(без питания)");

	ADV_SERVICE("2В", "<b>Вагон с услугами</b>");
	ADV_SERVICE("2Е", "<b>Эконом-класс<b><br/>(вагон с услугами, наличие установки кондиционирования воздуха)");
	ADV_SERVICE("2К", "<b>Купейный</b><br/>(вагон без услуг)");
	ADV_SERVICE("2Л", "<b>Купейный</b><br/>(вагон без услуг, наличие установки кондиционирования воздуха)");
	ADV_SERVICE("2С", "<b>Вагон без услуг</b><br/>(наличие установки кондиционирования воздуха)");
	ADV_SERVICE("2У", "<b>Купейный</b><br/>(вагон с услугами)");
	ADV_SERVICE("2Э", "<b>Эконом-класс</b><br/>(вагон с услугами, наличие установки кондиционирования воздуха)");

	ADV_SERVICE("3О", "<b>Общий</b>");
	ADV_SERVICE("3П", "<b>Плацкартный</b>");
	ADV_SERVICE("3Э", "<b>Плацкартный</b><br/>(наличие установки кондиционирования воздуха)");

	ADV_SERVICE("--", "<b>Класс обслуживания не указан</b>");

	ADV_CAT("У0", "<b>Вагон повышенной комфортности</b>")
			else ADV_CAT("У", "<b>Вагон повышенной комфортности</b><br/>(с питанием)");
	ADV_CAT("Э", "<b>Вагон эконом-класса</b>");
	ADV_CAT("НФ", "<b>Нефирменный вагон фирменного поезда</b>")
			else ADV_CAT("Ф", "<b>Фирменный вагон</b>");
	ADV_CAT("БН", "<i>Без указания номера места в вагоне</i>")
			else ADV_CAT("Б", "<b>Вагон бизнес-класса</b>");
	ADV_CAT("И", "<i>Обеспечен вход для инвалидов с коляской</i>");
	ADV_CAT("МЖ", "<i>Продажа купе с мужскими/женскими местами</i>");
}

void ParseTrainData::Print() {
	if (m_TableType->currentIndex() == TABLE_FAV) {
		for (TrainDataList::iterator It = m_FavData.begin(); It != m_FavData.end(); It++) {
			It->Favorite = true;
		}
	}
	const TrainDataList & List = * m_CurrentData;
	m_TableEventHandler->Reset();
	int SelectedRow = m_Table->currentRow();
	int SelectedCol = m_Table->currentColumn();
	QTableWidgetItem * item;
	int CurrentRow = 0;
	m_Table->setRowCount(0);
	m_Table->setRowCount(1);
	m_Table->clearSpans();
	int TrainRow = 0, ClassRow = 0;
	int UP, LP, USP, LSP, OP;
	int Count = 0;
	if (m_Collapsable) {
		m_Table->hideColumn(COL_NUMBER);
	}
	else {
		m_Table->showColumn(COL_NUMBER);
	}
	if (m_SeatsDetailsVisible) {
		m_Table->showColumn(COL_UPPERPLACES);
		m_Table->showColumn(COL_LOWERPLACES);
		m_Table->showColumn(COL_UPPERSIDEPLACES);
		m_Table->showColumn(COL_LOWERSIDEPLACES);
		m_Table->showColumn(COL_OTHERPLACES);

		m_Table->hideColumn(COL_TOTALPLACES);
	}
	else {
		m_Table->hideColumn(COL_UPPERPLACES);
		m_Table->hideColumn(COL_LOWERPLACES);
		m_Table->hideColumn(COL_UPPERSIDEPLACES);
		m_Table->hideColumn(COL_LOWERSIDEPLACES);
		m_Table->hideColumn(COL_OTHERPLACES);

		m_Table->showColumn(COL_TOTALPLACES);
	}
	foreach (TrainDataStruct Train, List) {
		if (Train.Visible == false) {
			continue;
		}
		TrainRow = CurrentRow;
		QColor BackgroundColor = Count % 2 == 0 ? QColor(255, 255, 255, 255) : QColor(220, 220, 255, 255);
		item = new QTableWidgetItem(Train.Name);
		item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
		item->setBackgroundColor(BackgroundColor);
		item->setData(ROLE_TRAIN_ID, Train.Id);
		item->setData(ROLE_FAVORITE, Train.Favorite);
		item->setIcon(Train.Favorite ? QIcon((":/railworm/star.png")) : QIcon((":/railworm/empty_star.png")));
		m_Table->setItem(CurrentRow, COL_NAME, item);
		item = new QTableWidgetItem(Train.Path);
		item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
		item->setBackgroundColor(BackgroundColor);
		m_Table->setItem(CurrentRow, COL_PATH, item);
		item = new QTableWidgetItem(Train.Start);
		item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
		item->setBackgroundColor(BackgroundColor);
		m_Table->setItem(CurrentRow, COL_START, item);
		item = new QTableWidgetItem(Train.End);
		item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
		item->setBackgroundColor(BackgroundColor);
		m_Table->setItem(CurrentRow, COL_END, item);
		item = new QTableWidgetItem(Train.Delta);
		item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
		item->setBackgroundColor(BackgroundColor);
		m_Table->setItem(CurrentRow, COL_DELTA, item);
		qSort(Train.Class.begin(), Train.Class.end(), PriceSort);
		if (Train.Class.size())  foreach (ClassesStruct Class, Train.Class) {
			if (Class.Visible == false) {
				continue;
			}
			ClassRow = CurrentRow;
			item = new QTableWidgetItem(Class.AdvDesc.Class);
			item->setToolTip(Class.AdvDesc.Service);
			item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
			item->setBackgroundColor(BackgroundColor);
			item->setData(ROLE_TRAIN_ID, Train.Id);
			item->setData(ROLE_CLASS_ID, Class.Id);
			m_Table->setItem(CurrentRow, COL_CLASS, item);
			item = new QTableWidgetItem(Class.Category);
			item->setToolTip(Class.AdvDesc.Category);
			item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
			item->setBackgroundColor(BackgroundColor);
			m_Table->setItem(CurrentRow, COL_CATEGORY, item);
			item = new QTableWidgetItem(Class.Price);
			item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
			item->setBackgroundColor(BackgroundColor);
			m_Table->setItem(CurrentRow, COL_PRICE, item);
			UP = 0; LP = 0; USP = 0; LSP = 0; OP = 0;
			foreach (CarDataStruct Car, Class.Car) {
				if (m_Collapsable) {
					UP += Car.UpperPlaces.toInt();
					LP += Car.LowerPlaces.toInt();
					USP += Car.UpperSidePlaces.toInt();
					LSP += Car.LowerSidePlaces.toInt();
					OP += Car.OtherPlaces.toInt();
				}
				else {
					item = new QTableWidgetItem(Car.Number);
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					item->setData(ROLE_TRAIN_ID, Train.Id);
					item->setData(ROLE_CLASS_ID, Class.Id);
					m_Table->setItem(CurrentRow, COL_NUMBER, item);
					UP = Car.UpperPlaces.toInt();
					item = new QTableWidgetItem(QString::number(UP));
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_UPPERPLACES, item);
					LP = Car.LowerPlaces.toInt();
					item = new QTableWidgetItem(QString::number(LP));
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_LOWERPLACES, item);
					USP = Car.UpperSidePlaces.toInt();
					item = new QTableWidgetItem(QString::number(USP));
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_UPPERSIDEPLACES, item);
					LSP = Car.LowerSidePlaces.toInt();
					item = new QTableWidgetItem(QString::number(LSP));
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_LOWERSIDEPLACES, item);
					OP = Car.OtherPlaces.toInt();
					item = new QTableWidgetItem(QString::number(OP));
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_OTHERPLACES, item);

					item = new QTableWidgetItem(QString::number(UP + LP + USP + LSP + OP));
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_TOTALPLACES, item);

					CurrentRow = m_Table->rowCount();
					m_Table->setRowCount(CurrentRow + 1);
				}
			}
			if (m_Collapsable) {
					item = new QTableWidgetItem("*");
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_NUMBER, item);
					item = new QTableWidgetItem(UP ? QString::number(UP) : "");
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_UPPERPLACES, item);
					item = new QTableWidgetItem(LP ? QString::number(LP) : "");
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_LOWERPLACES, item);
					item = new QTableWidgetItem(USP ? QString::number(USP) : "");
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_UPPERSIDEPLACES, item);
					item = new QTableWidgetItem(LSP ? QString::number(LSP) : "");
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_LOWERSIDEPLACES, item);
					item = new QTableWidgetItem(OP ? QString::number(OP) : "");
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_OTHERPLACES, item);

					item = new QTableWidgetItem(QString::number(UP + LP + USP + LSP + OP));
					item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
					item->setBackgroundColor(BackgroundColor);
					m_Table->setItem(CurrentRow, COL_TOTALPLACES, item);

					CurrentRow = m_Table->rowCount();
					m_Table->setRowCount(CurrentRow + 1);
			}
			for (int Col = COL_CLASS; Col <= COL_PRICE; Col++) {
				if (CurrentRow - ClassRow > 1) {
					m_Table->setSpan(ClassRow, Col, CurrentRow - ClassRow, 1);
				}
			}
		}
		else {
			CurrentRow = m_Table->rowCount();
			m_Table->setRowCount(CurrentRow + 1);
		}
		for (int Col = COL_NAME; Col <= COL_DELTA; Col++) {
			if (CurrentRow - TrainRow > 1) {
				m_Table->setSpan(TrainRow, Col, CurrentRow - TrainRow, 1);
			}
		}
		Count++;
	}
	m_Table->setRowCount(CurrentRow);
	m_Table->setCurrentCell(SelectedRow, SelectedCol);
	m_Table->horizontalHeader()->setVisible(m_Table->rowCount() > 0);
}

QTableWidget * ParseTrainData::Table() {
	return m_Table;
}

QWidget * ParseTrainData::Widget() {
	return m_Widget;
}

QLineEdit * ParseTrainData::Filter() {
	return m_Filter;
}
void ParseTrainData::Cancel() {
	jinn.Cancel();
}

void ParseTrainData::SetCollapsable(bool State) {
	m_Collapsable = State;
}

void ParseTrainData::SetSeatsDetailsVisible(bool State) {
	m_SeatsDetailsVisible = State;
}

const TrainDataList & ParseTrainData::SessionData() {
	return * m_CurrentData;
}

QDateTime StringToDateTime(QString Str) {
	return QDateTime::fromString(Str.simplified(), "dd.MM hh:mm");
}

int g_SortColumn = -1;
bool TrainDataSort(TrainDataStruct & td1, TrainDataStruct & td2) {
	if (td1.Visible != td2.Visible) {
		if (td1.Visible) {
			return true;
		}
		if (td2.Visible) {
			return false;
		}
	}
	float Price1 = 1000000000.0;
	float Price2 = 1000000000.0;
	switch (g_SortColumn) {
		case ParseTrainData::COL_NAME:
			return td1.Name.localeAwareCompare(td2.Name) < 0;
		case ParseTrainData::COL_PATH:
			return td1.Path.localeAwareCompare(td2.Path) < 0;
		case ParseTrainData::COL_START:
			return StringToDateTime(td1.Start) < StringToDateTime(td2.Start);
		case ParseTrainData::COL_END:
			return StringToDateTime(td1.End) < StringToDateTime(td2.End);
		case ParseTrainData::COL_DELTA:
			return QTime::fromString(td1.Delta.simplified(), "hh:mm") < QTime::fromString(td2.Delta.simplified(), "hh:mm");
		case ParseTrainData::COL_PRICE:
			foreach (ClassesStruct Class, td1.Class) {
				if (Class.Visible) {
					Price1 = qMin(Class.Price.replace("&nbsp;", "").split("-").at(0).toFloat(), Price1);
				}
			}
			foreach (ClassesStruct Class, td2.Class) {
				if (Class.Visible) {
					Price2 = qMin(Class.Price.replace("&nbsp;", "").split("-").at(0).toFloat(), Price2);
				}
			}
			return Price1 <= Price2;
	}
	return false;
}

void ParseTrainData::SortBy(int Col) {
	if (((Col >= COL_NAME) && (Col <= COL_DELTA)) || (Col == COL_PRICE)) {
		g_SortColumn = Col;
		qSort(m_CurrentData->begin(), m_CurrentData->end(), TrainDataSort);
	}
}

void ParseTrainData::OnSort(int Index) {
	SortBy(Index);
	Print();
}

void ParseTrainData::OnFilterChanged() {

	QString FilterText = m_Filter->text();
	int VisibleCount = 0;
	for (TrainDataList::iterator TrainData_It = m_CurrentData->begin(); TrainData_It != m_CurrentData->end(); TrainData_It++) {
		TrainData_It->Visible = Contains(* TrainData_It, FilterText);
		if (TrainData_It->Visible) {
			VisibleCount++;
		}
	}
	bool NoOneTrain = (VisibleCount == 0);
	for (TrainDataList::iterator TrainData_It = m_CurrentData->begin(); TrainData_It != m_CurrentData->end(); TrainData_It++) {
		ClassesList & List = TrainData_It->Class;
		VisibleCount = 0;
		for (ClassesList::iterator Class_It = List.begin(); Class_It != List.end(); Class_It++) {
			if ((Class_It->Visible = Contains(* Class_It, FilterText, NoOneTrain)) == true) {
				VisibleCount++;
			}
		}
		if (VisibleCount > 0) {
			if (NoOneTrain) {
				TrainData_It->Visible = true; // показываем все, раз уж ни одного нет
			}
		}
		else if (TrainData_It->Visible) {
			for (ClassesList::iterator Class_It = List.begin(); Class_It != List.end(); Class_It++) {
				Class_It->Visible = true;
			}
		}
	}


	Print();
}

bool ParseTrainData::Contains(const TrainDataStruct & TrainData, const QString & Text) {
	if (Text.simplified().isEmpty()) {
		return true;
	}
	QStringList List = Text.simplified().split(" ", QString::SkipEmptyParts);
	int Count = 0;
	bool Found;
	foreach (QString Line, List) {
		Found = false;
		if (TrainData.Name.contains(Line, Qt::CaseInsensitive)) {
			Found = true;
		}
		if (TrainData.Path.contains(Line, Qt::CaseInsensitive)) {
			Found = true;
		}
		if (Found) {
			Count++;
		}
	}
	return (Count > 0);
}

bool ParseTrainData::Contains(const ClassesStruct & ClassData, const QString & Text, bool Exact) {
	if (Text.simplified().isEmpty()) {
		return true;
	}
	QStringList List = Text.simplified().split(" ", QString::SkipEmptyParts);
	int Count = 0;
	bool Found;
	foreach (QString Line, List) {
		Found = false;
		if (Line.contains(".")) {
			if (ClassData.Price.contains(Line, Qt::CaseInsensitive)) {
				Found = true;
			}
		}
		if (Line.contains(">")) {
			if (ClassData.Price.simplified().split("-").at(0).toFloat() > Line.remove(0, 1).toFloat()) {
				Found = true;
			}
		}
		if (Line.contains("<")) {
			if (ClassData.Price.simplified().split("-").at(0).toFloat() < Line.remove(0, 1).toFloat()) {
				Found = true;
			}
		}
		if (ClassData.Category.contains(Line, Qt::CaseInsensitive)) {
			Found = true;
		}
		if (ClassData.Class.contains(Line, Qt::CaseInsensitive)) {
			Found = true;
		}
		if (ClassData.AdvDesc.Category.contains(Line, Qt::CaseInsensitive)) {
			Found = true;
		}
		if (ClassData.AdvDesc.Class.contains(Line, Qt::CaseInsensitive)) {
			Found = true;
		}
		if (ClassData.AdvDesc.Service.contains(Line, Qt::CaseInsensitive)) {
			Found = true;
		}
		if (Found) {
			Count++;
		}
	}
	return Exact ? Count == List.size() : Count > 0;
}

QString ParseTrainData::ExtractUrl(int Row, int Column) {
	QString Url;
	if (m_Table->item(Row, COL_NAME)) {
		int Id = m_Table->item(Row, COL_NAME)->data(ROLE_TRAIN_ID).toInt();
		foreach (TrainDataStruct td, * m_CurrentData) {
			if (td.Id == Id) {
				switch (Column) {
					case COL_NAME:
						Url = rzd::PassHost() + td.NameUrl;
						break;
					case COL_PATH:
						Url = rzd::PassHost() + td.PathUrl;
						break;
				}
				break;
			}
		}
		if (Url.isEmpty() == false) {
			if (Url.contains("http", Qt::CaseInsensitive) == false) {
				Url = "http://" + Url;
			}
		}
	}
	return Url;
}

void ParseTrainData::OpenUrl(int Row, int Column) {
	QString Url = ExtractUrl(Row, Column);
	if (Url.isEmpty() == false) {
		rzd::OpenUrl(QUrl::fromEncoded(Url.toAscii()));
	}
	if ((Column == COL_PRICE) || (Column == COL_NUMBER)) {
		Order(Row, Column);
	}
}

void ParseTrainData::MarkFavorite(int Row, int Column) {
	if (Column == COL_NAME) {
		QTableWidgetItem * Item = m_Table->item(Row, Column);
		QPoint pt = m_Table->mapFromGlobal(QCursor::pos());
		QRect rect = m_Table->visualItemRect(Item);
		QRect icon_rect(rect.left(), rect.top() + m_Table->horizontalHeader()->height() - 10 + rect.height() / 2, 20, 20);
		if (icon_rect.contains(pt)) {
			bool State = Item->data(ROLE_FAVORITE).toBool();
			int Id = Item->data(ROLE_TRAIN_ID).toInt();
			TrainDataList::iterator Ses_It = FindById(m_SessionData, Id);
			TrainDataList::iterator Fav_It = FindById(m_FavData, Id);
			if (State) {
				Item->setIcon(QIcon(":/railworm/empty_star.png"));
				if ((Fav_It != m_FavData.end())) {
					m_FavData.erase(Fav_It);
				}
			}
			else {
				Item->setIcon(QIcon(":/railworm/star.png"));
				if ((Fav_It == m_FavData.end()) && (Ses_It != m_SessionData.end()) && (m_TableType->currentIndex() == TABLE_ALL)) {
					m_FavData.append(* Ses_It);
				}
			}
			Item->setData(ROLE_FAVORITE, !State);

			if (Ses_It != m_SessionData.end()) {
				Ses_It->Favorite = !State;
			}
			if (m_TableType->currentIndex() == TABLE_FAV) {
				Print();
			}
		}
	}
}

TrainDataList::iterator ParseTrainData::FindById(const TrainDataList & List, int Id) {
	for (TrainDataList::iterator Iter = const_cast<TrainDataList &>(List).begin(); Iter != const_cast<TrainDataList &>(List).end(); Iter++) {
		if (Iter->Id == Id) {
			return Iter;
		}
	}
	return const_cast<TrainDataList &>(List).end();
}

ClassesList::iterator ParseTrainData::FindClassById(const TrainDataList::iterator & _it, int _Class_Id) {
	for (ClassesList::iterator Iter = const_cast<ClassesList &>(_it->Class).begin(); Iter != const_cast<ClassesList &>(_it->Class).end(); Iter++) {
		if (Iter->Id == _Class_Id) {
			return Iter;
		}
	}
	return const_cast<ClassesList &>(_it->Class).end();
}

void ParseTrainData::TableTypeChanged(int Type) {
	m_CurrentData = Type == TABLE_ALL ? & m_SessionData : & m_FavData;
	Print();
}

void ParseTrainData::Order(int Row, int Column) {
	if ((Column == COL_PRICE) || (Column == COL_NUMBER)) {
		if (m_CurrentData == 0) {
			return;
		}
		qDebug() << "order selected";

		QTableWidgetItem * _item = 0;

// извлекаем элемент из таблицы
		if (Column == COL_PRICE) {
			_item = m_Table->item(Row, COL_CLASS);
		}
		else {
			_item = m_Table->item(Row, COL_NUMBER);
		}
		if (_item == 0) {
			return;
		}

// извлекаем id поезда и класса из элемента таблицы
		int _train_id = _item->data(ROLE_TRAIN_ID).toInt();
		int _class_id = _item->data(ROLE_CLASS_ID).toInt();
		qDebug() << "order id = " << _train_id;

// ищем id в структуре данных
		TrainDataList::iterator _train_it = FindById(* m_CurrentData, _train_id);
		if (_train_it == m_CurrentData->end()) {
			return;
		}
		ClassesList::iterator _class_it = FindClassById(_train_it, _class_id);
		if (_class_it == _train_it->Class.end()) {
			return;
		}

// оставляем только один (найденный) класс
		TrainDataStruct tds = * _train_it;
		tds.Class.clear();
		tds.Class << * _class_it;

		if (Column == COL_NUMBER) {
			// если заказ по номеру вагона, то оставляем только один (найденный) вагон
			int _car = _item->text().toInt();
			CarDataStruct cds;
			foreach (const CarDataStruct & _cds, tds.Class.at(0).Car) {
				if (_cds.Number.toInt() == _car) {
					cds = _cds;
					break;
				}
			}
			const_cast<CarDataList &>(tds.Class.at(0).Car).clear();
			const_cast<CarDataList &>(tds.Class.at(0).Car) << cds;
		}

		emit OrderRequested(tds);
	}
}
